﻿using Microsoft.Scripting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Scala.Compiler
{
    internal struct TokenWithSpan
    {
        private readonly Token _token;
        private readonly IndexSpan _span;

        public TokenWithSpan(Token token,IndexSpan span)
        {
            _token = token;
            _span = span;
        }

        public IndexSpan Span
        {
            get { return _span; }
        }

        public Token Token
        {
            get { return _token; }
        }
    }

    public abstract class Token
    {
        private readonly TokenKind _kind;

        protected Token(TokenKind kind)
        {
            _kind = kind;
        }

        public bool IsLiteral()
        {
            if (_kind >= TokenKind.CHARLIT && _kind <= TokenKind.INTERPOLATIONID)
            {
                return true;
            }
            else return false;
        }

        public bool IsIdentifier()
        {
            if (_kind == TokenKind.IDENTIFIER || _kind == TokenKind.BACKQUOTED_IDENT)
            {
                return true;
            }
            else return false;
        }

        public TokenKind Kind
        {
            get { return _kind; }
        }

        public virtual object Value
        {
            get { throw new NotSupportedException("This token has no value"); }
        }

        public override string ToString()
        {
            return base.ToString() + "(" + _kind + ")";
        }

        public abstract String Image
        {
            get;
        }
    }

    public class ConstantValueToken : Token
    {
        private readonly object _value;

        public ConstantValueToken(object value):base(TokenKind.Constant)
        {
            _value = value;
        }

        public object Constant
        {
            get { return this._value; }
        }

        public override object Value
        {
            get
            {
                return _value;
            }
        }

        public override string Image
        {
            get { return _value == null ? "None" : _value.ToString(); }
        }
    }
    
    public class ErrorToken : Token
    {
        private readonly String _message;

        public ErrorToken(String message)
            : base(TokenKind.Error)
        {
            _message = message;
        }

        public String Message
        {
            get { return _message; }
        }

        public override String Image
        {
            get { return _message; }
        }

        public override object Value
        {
            get { return _message; }
        }
    }

    public class IncompleteStringErrorToken : ErrorToken
    {
        private readonly string _value;

        public IncompleteStringErrorToken(string message, string value)
            : base(message)
        {
            _value = value;
        }

        public override string Image
        {
            get
            {
                return _value;
            }
        }

        public override object Value
        {
            get
            {
                return _value;
            }
        }
    }
    sealed class UnicodeStringToken : ConstantValueToken
    {
        public UnicodeStringToken(object value)
            : base(value)
        {
        }
    }

    public sealed class CommentToken : Token
    {
        private readonly string _comment;

        public CommentToken(string comment)
            : base(TokenKind.COMMENT)
        {
            _comment = comment;
        }

        public string Comment
        {
            get { return _comment; }
        }

        public override string Image
        {
            get { return _comment; }
        }

        public override object Value
        {
            get { return _comment; }
        }
    }

    public class NameToken : Token
    {
        private readonly string _name;

        public NameToken(string name,TokenKind kind)
            : base(kind)
        {
            _name = name;
        }

        public string Name
        {
            get { return this._name; }
        }

        public override object Value
        {
            get { return _name; }
        }

        public override String Image
        {
            get
            {
                return _name;
            }
        }
    }

    public class TermNameToken:NameToken
    {
        public TermNameToken(string name,TokenKind kind) : base(name,kind) { }
        
        public bool isTermName
        {
            get { return true; }
        }
        public bool isTypeName
        {
            get { return false; }
        }
        public TypeNameToken toTypeName()
        {
            return new TypeNameToken(Name,TokenKind.TYPE);
        }
    }

    public class TypeNameToken:NameToken
    {
        public TypeNameToken(string name,TokenKind kind) : base(name,kind) { }
        public bool isTermName { get { return false; } }
        public bool isTypeName { get { return true; } }
        public TermNameToken toTermName() { return new TermNameToken(Name,TokenKind.Name); }
    }
    public class OperatorToken : Token
    {
        private readonly int _precedence;
        private readonly string _image;

        public OperatorToken(TokenKind kind, string image, int precedence)
            : base(kind)
        {
            _image = image;
            _precedence = precedence;
        }

        public int Precedence
        {
            get { return _precedence; }
        }

        public override object Value
        {
            get { return _image; }
        }

        public override String Image
        {
            get { return _image; }
        }
    }

    public class SymbolToken : Token
    {
        private readonly string _image;

        public SymbolToken(TokenKind kind, String image)
            : base(kind)
        {
            _image = image;
        }

        public String Symbol
        {
            get { return _image; }
        }

        public override object Value
        {
            get { return _image; }
        }

        public override String Image
        {
            get { return _image; }
        }
    }
}
